unit uSBD_Crypto_Cipher;
interface
uses Classes;

type

TSymetricKey = class
  public
    constructor LoadFromStream( Stream: TStream);   virtual; abstract;
    procedure   SaveToStream( Stream: TStream);     virtual; abstract;
  end;

ICipher = interface
  ['{CB927B43-8A02-4332-B844-A174D1D6B705}']
    function  GenerateKey( Seed: TMemoryStream): TSymetricKey;
    procedure Encrypt_Block( Key: TSymetricKey; Plaintext{in}, Ciphertext{out}: TMemoryStream);
    procedure Decrypt_Block( Key: TSymetricKey; Plaintext{out}, Ciphertext{in}: TMemoryStream);
    function  BlockSize: integer;  // in units of bits. Must be a multiple of 8.
    function  SeedByteSize: integer; // Size that the input of the GenerateKey must be.
    function  DisplayName: string;
    function  ProgId: string;
  end;


TBlockChainLink = class
  protected
    FKey: TSymetricKey;
    FIV: TMemoryStream;
    FCipher: ICipher;

    constructor BaseCreate(
      Key1: TSymetricKey;   // Will be referenced, not cloned.
      IV1: TMemoryStream;   // Will be cloned.
      Cipher1: ICipher);    // Will be referenced, not cloned.

  public
    procedure Chain_Encrypt_Block(
      Plaintext{ in}, Ciphertext{ out}: TMemoryStream);   virtual; abstract;

    procedure Chain_Decrypt_Block(
      Plaintext{ out}, Ciphertext{ in}: TMemoryStream);   virtual; abstract;

    destructor Destroy; override;
  end;


IBlockChainingModel = interface
  ['{7ED854DF-5270-41F7-820A-65BF9B5E1D35}']

  function Chain_Encrypt_FirstBlock(
    Key: TSymetricKey;
    InitializationVector, Plaintext{ in}, Ciphertext{ out}: TMemoryStream;
    const Cipher: ICipher): TBlockChainLink;

  function Chain_Decrypt_FirstBlock(
    InitializationVector, Plaintext{ out}, Ciphertext{ in}: TMemoryStream;
    const Cipher: ICipher): TBlockChainLink;

  function  DisplayName: string;
  function  ProgId: string;
  end;



  TDCP_cipher= class(TComponent)
  public
    procedure Init(const Key; Size: longword; InitVector: pointer); virtual;
      { Do key setup based on the data in Key, size is in bits }
    procedure InitStr(const Key: string; HashType: TDCP_hashclass);
      { Do key setup based on a hash of the key string }
    procedure Burn; virtual;
      { Clear all stored key information }
    procedure Reset; virtual;
      { Reset any stored chaining information }
    function EncryptStream(InStream, OutStream: TStream; Size: longword): longword;
      { Encrypt size bytes of data from InStream and place in OutStream }
    function DecryptStream(InStream, OutStream: TStream; Size: longword): longword;
      { Decrypt size bytes of data from InStream and place in OutStream }
    function EncryptString(const Str: string): string; virtual;
      { Encrypt a string and return Base64 encoded }
    function DecryptString(const Str: string): string; virtual;
      { Decrypt a Base64 encoded string }

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation






uses uStreamUtils;

{ TBlockChainLink }

constructor TBlockChainLink.BaseCreate(
  Key1: TSymetricKey; IV1: TMemoryStream; Cipher1: ICipher);
begin
FKey    := Key1; // Not owned
FIV     := CloneMemoryStream( IV1); // Owned.
FCipher := Cipher1    // Not owned
end;

destructor TBlockChainLink.Destroy;
begin
BurnMemoryStream( FIV);
FIV.Free;
inherited;
end;

end.
